from lxml import etree


text = """
<div>
  <ul>
    <li class="item-0"><a href="link1.html">first item</a></li>
    <li class="item-1"><a href="link2.html">second item</a></li>
    <li class="item-inactive"><a href="link3.html">third item</a></li>
    <li class="item-1"><a href="link4.html">fourth item</a></li>
    <li class="item-0"><a href="link5.html">fifth item</a></li>
  </ul>
</div>
"""

"""
  示例 1 属性匹配 获取class 为 item-0 的 li 节点  
"""
html = etree.HTML(text)
result = html.xpath("//li[@class='item-0']")
print(result)


"""
  示例2 文本获取  获取 li 节点中的文本
  
  所以说，如果要想获取子孙节点内部的所有文本，可以直接用 // 加 text 方法的方式，这样可以保证获取到最全面的文本信息，但是可能会夹杂一些换行符等特殊字符。如果想获取某些特定子孙节点下的所有文本，
  可以先选取到特定的子孙节点，然后再调用 text 方法获取其内部文本，这样可以保证获取的结果是整洁的。
"""

html = etree.HTML(text)
result = html.xpath("//li[@class='item-0']/a/text()")
print(result) # ['first item', 'fifth item']    两个a 的文本都被获取到了



html = etree.HTML(text)
result = html.xpath("//li[@class='item-0']//text()")  # text() 前面是// 也就是匹配li的子孙元素，这时候拿到a
print(result) # ['first item', 'fifth item']    两个a 的文本都被获取到了


# **********************************************************************************


"""
  示例3 获取属性，用@
  属性匹配是中括号加属性名和值来限定某个属性，如 [@href="link1.html"]，而此处的 @href 指的是获取节点的某个属性，二者需要做好区分
"""
html = etree.HTML(text)
result = html.xpath("//li/a/@href")
print(result) # ['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']


"""
  示例4 属性多值匹配 
  这样通过 contains 方法，给其第一个参数传入属性名称，第二个参数传入属性值，只要此属性包含所传入的属性值，就可以完成匹配了
"""

text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class,"li")]/a/text()')
print(result) # ['first item']


"""
 示例5 多属性匹配
 根据多个属性确定一个节点，这时就需要同时匹配多个属性。此时可以使用运算符 and 来连接
 这里的 and 其实是 XPath 中的运算符。另外，还有很多运算符，如 or、mod 等
"""
text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result) # ['first item']


"""
运算符	描述	   实　　例	返　回　值		
or	或	age=19 or age=20	如果 age 是 19，则返回 true。如果 age 是 21，则返回 false		
and	与	age>19 and age<21	如果 age 是 20，则返回 true。如果 age 是 18，则返回 false		
mod	计算除法的余数	5 mod 2	1		
`	`	计算两个节点集	`//book	//cd`	返回所有拥有 book 和 cd 元素的节点集
+	加法	6 + 4	10		
-	减法	6 - 4	2		
*	乘法	6 * 4	24		
div	除法	8 div 4	2		
=	等于	age=19	如果 age 是 19，则返回 true。如果 age 是 20，则返回 false		
!=	不等于	age!=19	如果 age 是 18，则返回 true。如果 age 是 19，则返回 false		
<	小于	age<19	如果 age 是 18，则返回 true。如果 age 是 19，则返回 false		
<=	小于或等于	<=19	如果 age 是 19，则返回 true。如果 age 是 20，则返回 false		
>	大于	age>19	如果 age 是 20，则返回 true。如果 age 是 19，则返回 false		
>=	大于或等于	age>=19	如果 age 是 19，则返回 true。如果 age 是 18，则返回 false	
此表参考来源：http://www.w3school.com.cn/xpath/xpath_operators.asp。

"""